/**
 ******************************************************************************
 * File Name          : FMC.c
 * Description        : This file provides code for the configuration
 *                      of the FMC peripheral.
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
 * All rights reserved.</center></h2>
 *
 * This software component is licensed by ST under BSD 3-Clause license,
 * the "License"; You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                        opensource.org/licenses/BSD-3-Clause
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "fmc.h"

/* USER CODE BEGIN 0 */
#include "delay.h"

uint8_t SDRAM_Send_Cmd(uint8_t bankx, uint8_t cmd, uint8_t refresh, uint16_t regval) {
	uint32_t target_bank = 0;
	FMC_SDRAM_CommandTypeDef Command;

	if (bankx == 0)
		target_bank = FMC_SDRAM_CMD_TARGET_BANK1;
	else if (bankx == 1)
		target_bank = FMC_SDRAM_CMD_TARGET_BANK2;
	Command.CommandMode = cmd;                                             //命令
	Command.CommandTarget = target_bank;                                   //目标SDRAM存储区域
	Command.AutoRefreshNumber = refresh;                                   //自刷新次�???
	Command.ModeRegisterDefinition = regval;                               //要写入模式寄存器的�??
	if (HAL_SDRAM_SendCommand(&hsdram1, &Command, 0XFFFF) == HAL_OK) //向SDRAM发�?�命�???
			{
		return 0;
	} else
		return 1;
}

//在指定地�?(WriteAddr+Bank5_SDRAM_ADDR)�?�?,连续写入n个字�?.
//pBuffer:字节指针
//WriteAddr:要写入的地址
//n:要写入的字节�?
void FMC_SDRAM_WriteBuffer(uint8_t *pBuffer, uint32_t WriteAddr, uint32_t n) {
	for (; n != 0; n--) {
		*(volatile uint8_t*) (Bank5_SDRAM_ADDR + WriteAddr) = *pBuffer;
		WriteAddr++;
		pBuffer++;
	}
}

//在指定地�?((WriteAddr+Bank5_SDRAM_ADDR))�?�?,连续读出n个字�?.
//pBuffer:字节指针
//ReadAddr:要读出的起始地址
//n:要写入的字节�?
void FMC_SDRAM_ReadBuffer(uint8_t *pBuffer, uint32_t ReadAddr, uint32_t n) {
	for (; n != 0; n--) {
		*pBuffer++ = *(volatile uint8_t*) (Bank5_SDRAM_ADDR + ReadAddr);
		ReadAddr++;
	}
}

//发�?�SDRAM初始化序�?
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram) {
	uint32_t temp = 0;

	//SDRAM控制器初始化完成以后还需要按照如下顺序初始化SDRAM
	SDRAM_Send_Cmd(0, FMC_SDRAM_CMD_CLK_ENABLE, 1, 0);       //时钟配置使能
	delay_us(500);                                           //至少延时200us
	SDRAM_Send_Cmd(0, FMC_SDRAM_CMD_PALL, 1, 0);             //对所有存储区预充�?
	SDRAM_Send_Cmd(0, FMC_SDRAM_CMD_AUTOREFRESH_MODE, 8, 0); //设置自刷新次�?
															 //配置模式寄存�?,SDRAM的bit0~bit2为指定突发访问的长度�?
	//bit3为指定突发访问的类型，bit4~bit6为CAS值，bit7和bit8为运行模�?
	//bit9为指定的写突发模式，bit10和bit11位保留位
	temp = (uint32_t) SDRAM_MODEREG_BURST_LENGTH_1 |           //设置突发长度:1(可以�?1/2/4/8)
			SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |         //设置突发类型:连续(可以是连�?/交错)
			SDRAM_MODEREG_CAS_LATENCY_2 |                 //设置CAS�?:3(可以�?2/3)
			SDRAM_MODEREG_OPERATING_MODE_STANDARD |       //设置操作模式:0,标准模式
			SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;         //设置突发写模�?:1,单点访问
	SDRAM_Send_Cmd(0, FMC_SDRAM_CMD_LOAD_MODE, 1, temp); //设置SDRAM的模式寄存器

	//刷新频率计数�?(以SDCLK频率计数),计算方法:
	//COUNT=SDRAM刷新周期/行数-20=SDRAM刷新周期(us)*SDCLK频率(Mhz)/行数
	//我们使用的SDRAM刷新周期�?64ms,SDCLK=200/2=100Mhz,行数�?8192(2^13).
	//�?�?,COUNT=64*1000*100/8192-20=677
	HAL_SDRAM_ProgramRefreshRate(hsdram, 677);
}
/* USER CODE END 0 */

SDRAM_HandleTypeDef hsdram1;

/* FMC initialization function */
void MX_FMC_Init(void) {
	/* USER CODE BEGIN FMC_Init 0 */

	/* USER CODE END FMC_Init 0 */

	FMC_SDRAM_TimingTypeDef SdramTiming = { 0 };

	/* USER CODE BEGIN FMC_Init 1 */

	/* USER CODE END FMC_Init 1 */

	/** Perform the SDRAM1 memory initialization sequence
	 */
	hsdram1.Instance = FMC_SDRAM_DEVICE;
	/* hsdram1.Init */
	hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
	hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
	hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
	hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
	hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
	hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2;
	hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
	hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
	hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
	hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
	/* SdramTiming */
	SdramTiming.LoadToActiveDelay = 2;
	SdramTiming.ExitSelfRefreshDelay = 8;
	SdramTiming.SelfRefreshTime = 6;
	SdramTiming.RowCycleDelay = 6;
	SdramTiming.WriteRecoveryTime = 4;
	SdramTiming.RPDelay = 2;
	SdramTiming.RCDDelay = 2;

	if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK) {
		Error_Handler();
	}

	/* USER CODE BEGIN FMC_Init 2 */
	SDRAM_Initialization_Sequence(&hsdram1);
	/* USER CODE END FMC_Init 2 */
}

static uint32_t FMC_Initialized = 0;

static void HAL_FMC_MspInit(void) {
	/* USER CODE BEGIN FMC_MspInit 0 */

	/* USER CODE END FMC_MspInit 0 */
	GPIO_InitTypeDef GPIO_InitStruct = { 0 };
	if (FMC_Initialized) {
		return;
	}
	FMC_Initialized = 1;

	/* Peripheral clock enable */
	__HAL_RCC_FMC_CLK_ENABLE();

	/** FMC GPIO Configuration
	 PF0   ------> FMC_A0
	 PF1   ------> FMC_A1
	 PF2   ------> FMC_A2
	 PF3   ------> FMC_A3
	 PF4   ------> FMC_A4
	 PF5   ------> FMC_A5
	 PC0   ------> FMC_SDNWE
	 PC2_C   ------> FMC_SDNE0
	 PC3_C   ------> FMC_SDCKE0
	 PF11   ------> FMC_SDNRAS
	 PF12   ------> FMC_A6
	 PF13   ------> FMC_A7
	 PF14   ------> FMC_A8
	 PF15   ------> FMC_A9
	 PG0   ------> FMC_A10
	 PG1   ------> FMC_A11
	 PE7   ------> FMC_D4
	 PE8   ------> FMC_D5
	 PE9   ------> FMC_D6
	 PE10   ------> FMC_D7
	 PE11   ------> FMC_D8
	 PE12   ------> FMC_D9
	 PE13   ------> FMC_D10
	 PE14   ------> FMC_D11
	 PE15   ------> FMC_D12
	 PD8   ------> FMC_D13
	 PD9   ------> FMC_D14
	 PD10   ------> FMC_D15
	 PD14   ------> FMC_D0
	 PD15   ------> FMC_D1
	 PG2   ------> FMC_A12
	 PG4   ------> FMC_BA0
	 PG5   ------> FMC_BA1
	 PG8   ------> FMC_SDCLK
	 PD0   ------> FMC_D2
	 PD1   ------> FMC_D3
	 PG15   ------> FMC_SDNCAS
	 PE0   ------> FMC_NBL0
	 PE1   ------> FMC_NBL1
	 */
	/* GPIO_InitStruct */
	GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14
			| GPIO_PIN_15;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.Alternate = GPIO_AF12_FMC;

	HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

	/* GPIO_InitStruct */
	GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_2 | GPIO_PIN_3;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.Alternate = GPIO_AF12_FMC;

	HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

	/* GPIO_InitStruct */
	GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_8 | GPIO_PIN_15;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.Alternate = GPIO_AF12_FMC;

	HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

	/* GPIO_InitStruct */
	GPIO_InitStruct.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_0
			| GPIO_PIN_1;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.Alternate = GPIO_AF12_FMC;

	HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

	/* GPIO_InitStruct */
	GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_0 | GPIO_PIN_1;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.Alternate = GPIO_AF12_FMC;

	HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

	/* USER CODE BEGIN FMC_MspInit 1 */

	/* USER CODE END FMC_MspInit 1 */
}

void HAL_SDRAM_MspInit(SDRAM_HandleTypeDef *sdramHandle) {
	/* USER CODE BEGIN SDRAM_MspInit 0 */

	/* USER CODE END SDRAM_MspInit 0 */
	HAL_FMC_MspInit();
	/* USER CODE BEGIN SDRAM_MspInit 1 */

	/* USER CODE END SDRAM_MspInit 1 */
}

static uint32_t FMC_DeInitialized = 0;

static void HAL_FMC_MspDeInit(void) {
	/* USER CODE BEGIN FMC_MspDeInit 0 */

	/* USER CODE END FMC_MspDeInit 0 */
	if (FMC_DeInitialized) {
		return;
	}
	FMC_DeInitialized = 1;
	/* Peripheral clock enable */
	__HAL_RCC_FMC_CLK_DISABLE();

	/** FMC GPIO Configuration
	 PF0   ------> FMC_A0
	 PF1   ------> FMC_A1
	 PF2   ------> FMC_A2
	 PF3   ------> FMC_A3
	 PF4   ------> FMC_A4
	 PF5   ------> FMC_A5
	 PC0   ------> FMC_SDNWE
	 PC2_C   ------> FMC_SDNE0
	 PC3_C   ------> FMC_SDCKE0
	 PF11   ------> FMC_SDNRAS
	 PF12   ------> FMC_A6
	 PF13   ------> FMC_A7
	 PF14   ------> FMC_A8
	 PF15   ------> FMC_A9
	 PG0   ------> FMC_A10
	 PG1   ------> FMC_A11
	 PE7   ------> FMC_D4
	 PE8   ------> FMC_D5
	 PE9   ------> FMC_D6
	 PE10   ------> FMC_D7
	 PE11   ------> FMC_D8
	 PE12   ------> FMC_D9
	 PE13   ------> FMC_D10
	 PE14   ------> FMC_D11
	 PE15   ------> FMC_D12
	 PD8   ------> FMC_D13
	 PD9   ------> FMC_D14
	 PD10   ------> FMC_D15
	 PD14   ------> FMC_D0
	 PD15   ------> FMC_D1
	 PG2   ------> FMC_A12
	 PG4   ------> FMC_BA0
	 PG5   ------> FMC_BA1
	 PG8   ------> FMC_SDCLK
	 PD0   ------> FMC_D2
	 PD1   ------> FMC_D3
	 PG15   ------> FMC_SDNCAS
	 PE0   ------> FMC_NBL0
	 PE1   ------> FMC_NBL1
	 */

	HAL_GPIO_DeInit(GPIOF,
	GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);

	HAL_GPIO_DeInit(GPIOC, GPIO_PIN_0 | GPIO_PIN_2 | GPIO_PIN_3);

	HAL_GPIO_DeInit(GPIOG, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_8 | GPIO_PIN_15);

	HAL_GPIO_DeInit(GPIOE,
	GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_0 | GPIO_PIN_1);

	HAL_GPIO_DeInit(GPIOD, GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_0 | GPIO_PIN_1);

	/* USER CODE BEGIN FMC_MspDeInit 1 */

	/* USER CODE END FMC_MspDeInit 1 */
}

void HAL_SDRAM_MspDeInit(SDRAM_HandleTypeDef *sdramHandle) {
	/* USER CODE BEGIN SDRAM_MspDeInit 0 */

	/* USER CODE END SDRAM_MspDeInit 0 */
	HAL_FMC_MspDeInit();
	/* USER CODE BEGIN SDRAM_MspDeInit 1 */

	/* USER CODE END SDRAM_MspDeInit 1 */
}
/**
 * @}
 */

/**
 * @}
 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
